package com.zx._01_基础._012_反射;

import java.lang.reflect.Field;
import java.lang.reflect.GenericDeclaration;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class 泛型 {

    private Map<String, Integer> map;

    public static List<String> getList() {
        return null;
    }

    public static void main(String[] args) throws Exception {
        field();
        method();
        arraylist();
    }

    public static void field() throws Exception {
        //1.得到类中，指定的属性
        Class clazz = 泛型.class;
        Field f = clazz.getDeclaredField("map");

        //2.获得这个属性对应的类
        Class<?> a = f.getType();
        System.out.println("map的类型是：" + a);

        //3.获得这个属性的泛型类型
        Type type = f.getGenericType();
        getType(type);
        /*
            map的类型是：interface java.util.Map
            type is ParameterizedType
            原始类型是：interface java.util.Map
            第0个泛型类型是：class java.lang.String
            第1个泛型类型是：class java.lang.Integer
         */
    }

    public static void method() throws NoSuchMethodException {
        //1.得到类中，指定的属性
        Class clazz = 泛型.class;
        Method method = clazz.getMethod("getList");

        // 获得方法返回值的类型
        Type returnType = method.getGenericReturnType();
        getType(returnType);
        /*
            #####type is ParameterizedType#####
            原始类型是：interface java.util.List
            第0个泛型类型是：class java.lang.String
         */
    }

    public static void arraylist() throws Exception {
        List<String> l1 = new ArrayList<String>();

        // 直接获取时获取不到的，类型被虚拟机擦除了
        getType(l1.getClass().getGenericSuperclass());

        // 因为类型擦除，这里只能获得E，不能获得string。无法通过发射获得类型
        Method method = l1.getClass().getMethod("get", int.class);
        Type type = method.getGenericReturnType();
        getType(type);

        //防止类型擦除。
        //下边这组大括号非常重要
        l1 = new ArrayList<String>() {
        };
        // 直接获取时获取不到的，类型被虚拟机擦除了
        getType(l1.getClass().getGenericSuperclass());


    }

    public static void getType(Type type) {
        if (type instanceof ParameterizedType) {
            System.out.println("#####type is ParameterizedType#####");
            // 1. ParameterizedType 表示可以获得明确的泛型类型，泛型没有被擦除
            // （被参数化的类型，也就是增加了泛型限制的类型）
            //强制类型转换
            ParameterizedType t = (ParameterizedType) type;

            //6.获得它的原始类型
            Type rawType = t.getRawType();
            System.out.println("原始类型是：" + rawType);

            //7.获得泛型类型的泛型参数
            Type[] ts = t.getActualTypeArguments();
            for (int i = 0; i < ts.length; i++) {
                System.out.println("第" + i + "个泛型类型是：" + ts[i]);
            }
        } else if (type instanceof TypeVariable) {
            System.out.println("#####type is TypeVariable#####");
            // 2. TypeVariable 类型变量，无法获得明确的泛型是，使用该类型
            // 强制类型转换
            TypeVariable t = (TypeVariable) type;

            // 获得它的原始类型
            GenericDeclaration genericDeclaration = t.getGenericDeclaration();
            System.out.println("原始类型是：" + genericDeclaration);

            // 获得泛型类型的泛型参数
            System.out.println("泛型的类型：" + t.getName());

            Type[] bounds = t.getBounds();
            System.out.println("泛型的类型：" + bounds[0]);

        } else {
            System.out.println("#####泛型获取出错#####");
        }
    }

}
